/**
 * Copyright 2011 Google
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.appengine.codelab;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PropertyProjection;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

/**
 * This class defines the methods for basic operations of create, update & retrieve
 * 
 * @author 
 *
 */
public class Fraude {

	/**
	 * Create or update Fraude for a particular transacao. transacao has one to many
	 * relation-ship
	 * 
	 * @param fraude_name
	 *          : fraude name
	 * @param fraude_type
	 *          : fraude type
	 * @param fraude_forma_deteccao
	 *          : forma deteccao of the fraude
	 * @param fraude_data_deteccao
	 *          : data deteccao of the fraude          
	 * @return
	 */
  public static Entity createOrUpdateFraude(String fraude_id, String fraude_name, String fraude_type, String fraude_forma_deteccao, String fraude_data_deteccao, String trans_id) {
    Entity fraude = getSingleFraude(fraude_id);
    if (fraude == null) {
    	fraude = new Entity("Fraude", fraude_id);
    	fraude.setProperty("fraude_id", fraude_id);
    	fraude.setProperty("fraude_name", fraude_name);
    	fraude.setProperty("fraude_type", fraude_type);
    	fraude.setProperty("fraude_forma_deteccao", fraude_forma_deteccao);
    	fraude.setProperty("fraude_data_deteccao", fraude_data_deteccao);
    	fraude.setProperty("trans_id",trans_id);
    	
    } else {
      if (fraude_name != null && !"".equals(fraude_name)) {
    	  fraude.setProperty("fraude_name", fraude_name);
      }
      if (fraude_type != null && !"".equals(fraude_type)) {
    	  fraude.setProperty("fraude_type", fraude_type);
      }
      if (fraude_forma_deteccao != null && !"".equals(fraude_forma_deteccao)) {
    	  fraude.setProperty("fraude_forma_deteccao", fraude_forma_deteccao);
      }
      if (fraude_data_deteccao != null && !"".equals(fraude_data_deteccao)) {
    	  fraude.setProperty("fraude_data_deteccao", fraude_data_deteccao);
      }
      if( trans_id != null && ! trans_id.isEmpty() ){
    	  fraude.setProperty("trans_id",trans_id);
      }
    }
    Util.persistEntity(fraude);
    return fraude;
  }

  public static List<String> listarTiposFraudes()
  {
	    Query query = new Query("Fraude");
	    query.addProjection(new PropertyProjection("fraude_type", String.class));
	    query.setDistinct(true);

	    Iterable<Entity> iterable = DatastoreServiceFactory.getDatastoreService().prepare(query).asIterable();
	    List<String> tipos = new ArrayList<String>();
	    
	    for( Entity entity : iterable ){
	    	tipos.add( (String) entity.getProperty("fraude_type"));
	    }
	    
	    return tipos;
  }
  
	/**
	 * get All the fraudes in the list
	 * 
	 * @param kind
	 *          : fraude kind
	 * @return all the fraudes
	 */
  public static Iterable<Entity> getAllFraudes() {
    Iterable<Entity> entities = Util.listEntities("Fraude", null, null);
    return entities;
  }

 
	/**
	 * Get the fraude given the name
	 * 
	 * @param fraude_name
	 *          : fraude name
	 * @return fraude Entity
	 */
  public static Iterable<Entity> getFraude(String fraude_id) {
    Iterable<Entity> entities = Util.listEntities("Fraude", "fraude_id", fraude_id);
    return entities;
  }

	/**
	 * Get all the transacoes for a midia
	 * 
	 * @param kind
	 *          : fraude kind
	 * @param midiaName
	 *          : midia name
	 * @return: all fraudes of type midia
	 */
  public static Iterable<Entity> getFraudeForMidia(String kind, String midiaName) {
    Key ancestorKey = KeyFactory.createKey("Midia", midiaName);
    return Util.listChildren("Fraude", ancestorKey);
  }
	  /**
		 * Get all the fraude for a cliente
		 * 
		 * @param kind
		 *          : fraude kind
		 * @param clienteName
		 *          : cliente name
		 * @return: all fraude of type cliente
		 */
	public static Iterable<Entity> getFraudeForCliente(String kind, String clienteName) {
	  Key ancestorKey = KeyFactory.createKey("Cliente", clienteName);
	  return Util.listChildren("Fraude", ancestorKey);
	}

	/**
	 * Get all the fraudes for a cliente_name
	 * 
	 * @param kind
	 *            : fraude kind
	 * @param cliente_name
	 *            : cliente_name
	 * @return: all fraude of type cliente
	 */

	public static Iterable<Entity> getFraudeForCliente(String clienteName) {
        ArrayList<Entity> list = new ArrayList<Entity>();
        Iterable<Entity> fraudes = Util.listEntities("Fraude", null, null);
        for (Entity fraude : fraudes) {
                String transId = fraude.getProperty("trans_id").toString();
                Entity transacao = Transacao.getSingleTransacao(transId);
                String clienteId = transacao.getProperty("cliente_id").toString();
                Entity cliente = Cliente.getSingleCliente(clienteId);
                if (clienteName.equals(cliente.getProperty("cliente_name").toString())) {
                        list.add(fraude);
                }
        }
        return list;
}
	
	/**
	 * get Fraude with Fraude name
	 * 
	 * @param fraude_name
	 *          : get fraudeName
	 * @return fraude entity
	 */
  public static Entity getSingleFraude(String fraude_id) {
    Iterable<Entity> results = Util.listEntities("Fraude", "fraude_id", fraude_id);
    List<Entity> entity = new ArrayList<Entity>();
    for(Entity e : results)
      if(e!=null)
        entity.add(e);
      if (!entity.isEmpty()) {
        return (Entity)entity.remove(0);
      }
	  return null;
  }

	public static List<FraudePorFronteira> getFraudes(Date dataInicial, Date dataFinal, String tipoFraude) 
	{
		DatastoreService ds = Util.getDatastoreServiceInstance();
		Query query = new Query("Fraude");
		
		List<Filter> filtros = new ArrayList<Filter>();
		
		filtros.add( new FilterPredicate("fraude_data_deteccao", FilterOperator.GREATER_THAN_OR_EQUAL, Common.dateToInt(dataInicial).toString() ));
		filtros.add( new FilterPredicate("fraude_data_deteccao", FilterOperator.LESS_THAN_OR_EQUAL, Common.dateToInt(dataFinal).toString() ));
		
		if( ! tipoFraude.isEmpty() ){
			filtros.add( new FilterPredicate("fraude_type", FilterOperator.EQUAL, tipoFraude ));
		}
		
		query.setFilter( CompositeFilterOperator.and(filtros) );
		List<FraudePorFronteira> fraudes = new ArrayList<FraudePorFronteira>();
		
		for( Entity fraude : ds.prepare(query).asIterable() )
		{
			FraudePorFronteira fraudePorFronteira = new FraudePorFronteira();
			fraudePorFronteira.setData( Common.intToDate( fraude.getProperty("fraude_data_deteccao").toString() ) );
			fraudePorFronteira.setFormaDeteccao((String) fraude.getProperty("fraude_forma_deteccao"));
			fraudePorFronteira.setNome((String) fraude.getProperty("fraude_name") );
			fraudePorFronteira.setTipo((String) fraude.getProperty("fraude_type") );
			fraudePorFronteira.setId((String) fraude.getProperty("fraude_id") );
			fraudePorFronteira.setTransacao((String) fraude.getProperty("trans_id"));
			fraudes.add(fraudePorFronteira);
		}
	
		return fraudes;
	}

	public static Entity getLocalidadePorFraude( Entity fraude ){
		Entity transacao = Transacao.getSingleTransacao((String) fraude.getProperty("trans_id"));
		if( transacao != null ){  
			return Localidade.getSingleLocalidade(((String)transacao.getProperty("localidade_id")));
		}
		return null;
	}
	
	public static Map<String,List<Entity>> getFraudesPorFronteira(String idFraude, String tipoFronteira, String tipoFraude, Date dataInicial, Date dataFinal) 
	{
		Entity localidadePrincipal = getLocalidadePorFraude(getSingleFraude(idFraude));
		
		DatastoreService ds = Util.getDatastoreServiceInstance();
		Query query = new Query("Fraude");
		
		List<Filter> filtros = new ArrayList<Filter>();
		
		filtros.add( new FilterPredicate("fraude_data_deteccao", FilterOperator.GREATER_THAN_OR_EQUAL, Common.dateToInt(dataInicial) ));
		filtros.add( new FilterPredicate("fraude_data_deteccao", FilterOperator.LESS_THAN_OR_EQUAL, Common.dateToInt(dataFinal) ));

		if( ! tipoFraude.isEmpty() ){
			filtros.add( new FilterPredicate("fraude_type", FilterOperator.EQUAL, tipoFraude ));
		}
		
		Map<String,List<Entity>> localidades = new HashMap<String,List<Entity>>();
		
		for( Entity fraude : ds.prepare(query).asIterable() )
		{
			Entity localidade = getLocalidadePorFraude(fraude);
			
			if( localidade == null ){
				continue;
			}
			else if( "cidade".equals(tipoFronteira) && ! localidade.getProperty("localidade_city").equals(localidadePrincipal.getProperty("localidade_city"))){
				continue;
			}
			else if( "estado".equals(tipoFronteira) && ! localidade.getProperty("localidade_state").equals(localidadePrincipal.getProperty("localidade_state"))){
				continue;
			}
			else if( "pais".equals(tipoFronteira) && ! localidade.getProperty("localidade_country").equals(localidadePrincipal.getProperty("localidade_country"))){
				continue;
			}	
			
			if( idFraude.equals(fraude.getProperty("fraude_id")) ){
				continue;
			}
			
			if( "cidade".equals(tipoFronteira) ){
				String cep = "CEP: "+ localidade.getProperty("localidade_zip").toString().split("-")[0];
				if( localidades.containsKey(cep) ){
					localidades.get(cep).add(localidade);
				}else{
					localidades.put(cep,createList(localidade));
				}
			}
			else if( "estado".equals(tipoFronteira)){
				String cidade = "Cidade: "+ localidade.getProperty("localidade_city").toString();
				if( localidades.containsKey(cidade) ){
					localidades.get(cidade).add(localidade);
				}else{
					localidades.put(cidade,createList(localidade));
				}				
			}
			else if( "pais".equals(tipoFronteira)){
				String estado = "Estado: "+localidade.getProperty("localidade_state").toString();
				if( localidades.containsKey(estado) ){
					localidades.get(estado).add(localidade);
				}else{
					localidades.put(estado,createList(localidade));
				}
			}	
		}		
		return localidades;
	}

	private static List<Entity> createList(Entity localidade) {
		List<Entity> locialidades = new ArrayList<Entity>();
		locialidades.add(localidade);
		return locialidades;
	}
	// Metodo Adicionado por Anderson - US2 
	public static Iterable<Entity> getTransacaoFraudulentas(String trans_data_init,String trans_data_end) {
	    Iterable<Entity> entities = Util.listEntitiesFraudulentas("Fraude", "fraude_data_deteccao", trans_data_init, trans_data_end);
	    
	    return entities;
	}
	// Metodo Adicionado por Anderson - US13
		 public static Iterable<Entity> getFraudePeriodoTipo(String trans_data_init,String trans_data_end, String fraude_type) {
			    Iterable<Entity> entities = Util.listEntitiesFraudePeriodoTipo(trans_data_init, trans_data_end, fraude_type);
			    
			    return entities;
		   }
}
